package org.road0329.tools.proto_parse_tool.ems;

import org.road0329.tools.proto_parse_tool.constants.ProtocolMeter645_2007Constant;
import org.road0329.tools.proto_parse_tool.ems.dataobject.*;
import org.road0329.tools.proto_parse_tool.enums.*;
import org.road0329.tools.proto_parse_tool.utils.DateUtil;
import org.road0329.tools.proto_parse_tool.utils.NumberUtil;
import org.road0329.tools.proto_parse_tool.utils.ProtocolUtils;
import org.road0329.tools.proto_parse_tool.utils.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * Created by Administrator on 2018-09-18.
 */
@Component
public class Protocol645_07Util {
    private static Logger logger = LoggerFactory.getLogger(Protocol645_07Util.class);
    private static final short EVENT_POWER_CUT = 140;

    public static String[] DATAFLAG_OVERLOAD_RECORD = {"(上{}次){}相过载发生时刻"
            , "(上{}次){}相过载发生时刻正向有功总电能"
            , "(上{}次){}相过载发生时刻反向有功总电能"
            , "(上{}次){}相过载发生时刻组合无功{}总电能"
            , "(上{}次){}相过载发生时刻组合无功 2 总电能"
            , "(上{}次){}相过载发生时刻 A 相正向有功电能"
            , "(上{}次){}相过载发生时刻 A 相反向有功电能"
            , "(上{}次){}相过载发生时刻 A 相组合无功{}电能"
            , "(上{}次){}相过载发生时刻 A 相组合无功 2 电能"
            , "(上{}次){}相过载发生时刻 B 相正向有功电能"
            , "(上{}次){}相过载发生时刻 B 相反向有功电能"
            , "(上{}次){}相过载发生时刻 B 相组合无功{}电能"
            , "(上{}次){}相过载发生时刻 B 相组合无功 2 电能"
            , "(上{}次){}相过载发生时刻 C 相正向有功电能"
            , "(上{}次){}相过载发生时刻 C 相反向有功电能"
            , "(上{}次){}相过载发生时刻 C 相组合无功{}电能"
            , "(上{}次){}相过载发生时刻 C 相组合无功 2 电能"
            , "(上{}次){}相过载结束时刻"
            , "(上{}次){}相过载结束时刻正向有功总电能"
            , "(上{}次){}相过载结束时刻反向有功总电能"
            , "(上{}次){}相过载结束时刻组合无功{}总电能"
            , "(上{}次){}相过载结束时刻组合无功 2 总电能"
            , "(上{}次){}相过载结束时刻 A 相正向有功电能"
            , "(上{}次){}相过载结束时刻 A 相反向有功电能"
            , "(上{}次){}相过载结束时刻 A 相组合无功{}电能"
            , "(上{}次){}相过载结束时刻 A 相组合无功 2 电能"
            , "(上{}次){}相过载结束时刻 B 相正向有功电能"
            , "(上{}次){}相过载结束时刻 B 相反向有功电能"
            , "(上{}次){}相过载结束时刻 B 相组合无功{}电能"
            , "(上{}次){}相过载结束时刻 B 相组合无功 2 电能"
            , "(上{}次){}相过载结束时刻 C 相正向有功电能"
            , "(上{}次){}相过载结束时刻 C 相反向有功电能"
            , "(上{}次){}相过载结束时刻 C 相组合无功{}电能"
            , "(上{}次){}相过载结束时刻 C 相组合无功 2 电能"};
    public static PointCommInfo parseCommand(byte[] newBytes) throws Exception {

        PointCommInfo pointComm = new PointCommInfo();
        int len = ProtocolUtils.Unsignd(newBytes[9]);
        if (len > 0) {
            String dataFlag = makeDataSubtract33(ProtocolUtils.getByteToHexStringDesc(newBytes, 10, 4, "")).toUpperCase();
            TransitControlTypeEnum controlType = TransitControlTypeEnum.getEnmuByValue(dataFlag);
            String pointAddr;
            if (controlType != null) {
                Object result = null;
                switch (controlType) {
                    case FORWARD_ACTIVE_ENERGY:
                    case FORWARD_REACTIVE_ENERGY:
                    case REVERSE_ACTIVE_ENERGY:
                    case REVERSE_REACTIVE_ENERGY:
                    case LAST_FREEZE_DATA_BLOCK:
                    case U:
                    case I:
                    case P:
                    case Q:
                    case PF:
                    case FORWARD_ACTIVE_DEMAND:
                    case REVERSE_ACTIVE_DEMAND:
                    case FORWARD_REACTIVE_DEMAND:
                    case REVERSE_REACTIVE_DEMAND:
                    case POWER_CUT_EVENT:
                        pointAddr = ProtocolUtils.getByteToHexStringDesc(newBytes, 1, 6, "");
                        Integer pointId = 0;
                        List<Object> saveDataList = new ArrayList<>();
                        result = saveCallData(pointId, newBytes, saveDataList);
                        pointComm.setControlType(controlType.getKey());
                        pointComm.setResultObject(result);
                        pointComm.setCommAddr(pointAddr);
                        pointComm.setSaveDataList(saveDataList);
                        break;
                    case SERVER_IP_PORT:
                    case MODULE_VERSION:
                        pointComm = parseCallData(newBytes, pointComm);
                        break;

                    default:
                        logger.info("{}数据项 不支持", controlType.getValue());

                }
                return pointComm;
            }
        } else if (len == 0) {//确认帧
            pointComm.setResultData("确认帧");
        }
        return pointComm;
    }

    private static Object saveCallData(Integer pointId, byte[] byteValue, List<Object> saveDataList) throws Exception {
        String value = ProtocolUtils.getByteToHexStringDesc(byteValue, byteValue.length, "");
        int index = value.length();
        index -= 18;
        String c = value.substring(index, index + 2);

        Object result = null;
        if ("91".equalsIgnoreCase(c) || "B1".equalsIgnoreCase(c)) {// 正常应答
            // 判断数据长度
            index -= 2;
            int len = Integer.parseInt(value.substring(index, index + 2), 16);
            if (len == 0) {// 无数据
                throw new Exception("回传645数据帧数据内容长度为0");
            }
            // 应答透明转发内容,数据域全部要减33的,长度L之后 到 CS校验和之前
            index -= len * 2;
            String temp = value.substring(index, index + len * 2);
            temp = makeDataSubtract33(temp);
            // 判断数据项
            index = temp.length();
            index -= 8;
            String di = temp.substring(index, index + 8).toUpperCase();
            TransitControlTypeEnum controlType = TransitControlTypeEnum.getEnmuByValue(di);
            if (controlType == null) {
                logger.warn("di:{} 没有对应的数据项处理", di);
                return result;
            }

            // 数据域
            String data = temp.substring(0, index);
            switch (controlType) {
                case FORWARD_ACTIVE_ENERGY:
                case FORWARD_REACTIVE_ENERGY:
                case REVERSE_ACTIVE_ENERGY:
                case REVERSE_REACTIVE_ENERGY:
                    result = saveCumulant(controlType, data, pointId, saveDataList);
                    break;
                case LAST_FREEZE_DATA_BLOCK:
                    saveFreezeBlock(data, pointId, saveDataList);
                    break;
                case U:
                case I:
                case P:
                case Q:
                case PF:
                    saveInstant(controlType, data, pointId, saveDataList);
                    break;
                case FORWARD_ACTIVE_DEMAND:
                case REVERSE_ACTIVE_DEMAND:
                case FORWARD_REACTIVE_DEMAND:
                case REVERSE_REACTIVE_DEMAND:

                    result = saveDemand(controlType, data, pointId, saveDataList);
                    break;
                case POWER_CUT_EVENT:
                    saveEvent(controlType, data, pointId, saveDataList);
                default:
                    logger.info("{} 没有对应的处理方法", controlType.getValue());

            }
        }
        return result;
    }


    private static PowerDemand saveDemand(TransitControlTypeEnum controlType, String value, Integer pointId, List<Object> saveDataList) {
        int maxCount = 5;
        int length = 16;

        if (StringUtil.isEmpty(value) || value.length() != maxCount * length) {
            return null;
        }
        Date now = new Date();
        Date dataTime = DateUtil.getCyc15Minute(now);

        String tempValue;
        int index = 0;
        BigDecimal decimal;
        short tariff = 0;

        PowerDemand powerDemand = new PowerDemand();

        powerDemand.setDataTime(dataTime);
        for (short count = 0; count < maxCount; count++) {
            index = count * length;
            tempValue = value.substring(index, index + length);
            if (tempValue.indexOf("EE") == 0) {
                continue;
            }
            DataPowerDemand demand = new DataPowerDemand();
            demand.setPointId(pointId);
            demand.setDataTime(dataTime);
            tariff = (short) (4 - count);
            demand.setTariffType(tariff);
            switch (controlType) {
                case FORWARD_ACTIVE_DEMAND:
                    demand.setPowerType((short) BmTypeEnum.BM_ZY.getValue());
                    break;
                case FORWARD_REACTIVE_DEMAND:
                    demand.setPowerType((short) BmTypeEnum.BM_ZW.getValue());
                    break;
                case REVERSE_ACTIVE_DEMAND:
                    demand.setPowerType((short) BmTypeEnum.BM_FY.getValue());
                    break;
                case REVERSE_REACTIVE_DEMAND:
                    demand.setPowerType((short) BmTypeEnum.BM_FW.getValue());
                    break;
            }
            demand.setOccurTime(DateUtil.StrToDate(tempValue.substring(0, 10), DateUtil.TIME_NO_SEC_10));
            demand.setDemandMax(NumberUtil.convertValue(tempValue.substring(10, 16), 4));
            saveDataList.add(demand);
        }
        return powerDemand;
    }

    private static void saveInstant(TransitControlTypeEnum controlType, String value, Integer pointId, List<Object> saveDataList) {
        if (StringUtil.isEmpty(value) || value.length() < 3 || value.equalsIgnoreCase("EEE")) {
            logger.info("value is null or value'length is not enough.");
            return;
        }
        DataPowerInstant instant = new DataPowerInstant();
        instant.setPointId(pointId);
        Date now = new Date();
        Date dataTime = DateUtil.getCyc15Minute(now);
        instant.setDataTime(dataTime);
        instant.setAddTime(now);
        instant.setUpdateTime(now);

        boolean flag = true;
        switch (controlType) {
            case U:
                if (value.length() < 4 * 3) {
                    logger.info("value'length < 12, actual:{}.", value.length());
                    return;
                }
                instant.setUa(NumberUtil.convertValue(value.substring(8, 12), 1));
                instant.setUb(NumberUtil.convertValue(value.substring(4, 8), 1));
                instant.setUc(NumberUtil.convertValue(value.substring(0, 4), 1));
                if (instant.getUa() == null && instant.getUb() == null && instant.getUc() == null) {
                    flag = false;
                }
                break;
            case I:
                if (value.length() < 6 * 3) {
                    logger.info("value'length < 18, actual:{}.", value.length());
                    return;
                }
                instant.setIa(NumberUtil.convertValue(value.substring(12, 18), 3));
                instant.setIb(NumberUtil.convertValue(value.substring(6, 12), 3));
                instant.setIc(NumberUtil.convertValue(value.substring(0, 6), 3));
                if (instant.getIa() == null && instant.getIb() == null && instant.getIc() == null) {
                    flag = false;
                }
                break;
            case P:
                if (value.length() < 6 * 4) {
                    logger.info("value'length < 18, actual:{}.", value.length());
                    return;
                }
                instant.setP(NumberUtil.convertValue(value.substring(18, 24), 4));
                instant.setPa(NumberUtil.convertValue(value.substring(12, 18), 4));
                instant.setPb(NumberUtil.convertValue(value.substring(6, 12), 4));
                instant.setPc(NumberUtil.convertValue(value.substring(0, 6), 4));
                if (instant.getPa() == null && instant.getPb() == null && instant.getPc() == null && instant.getP() == null) {
                    flag = false;
                }
                break;
            case Q:
                if (value.length() < 6 * 4) {
                    logger.info("value'length < 18, actual:{}.", value.length());
                    return;
                }
                instant.setQ(NumberUtil.convertValue(value.substring(18, 24), 4));
                instant.setQa(NumberUtil.convertValue(value.substring(12, 18), 4));
                instant.setQb(NumberUtil.convertValue(value.substring(6, 12), 4));
                instant.setQc(NumberUtil.convertValue(value.substring(0, 6), 4));
                if (instant.getQa() == null && instant.getQb() == null && instant.getQc() == null && instant.getQ() == null) {
                    flag = false;
                }
                break;
            case PF:
                if (value.length() < 4 * 4) {
                    logger.info("value'length < 18, actual:{}.", value.length());
                    return;
                }
                instant.setPf(NumberUtil.convertValue(value.substring(12, 16), 3));
                instant.setPfa(NumberUtil.convertValue(value.substring(8, 12), 3));
                instant.setPfb(NumberUtil.convertValue(value.substring(4, 8), 3));
                instant.setPfc(NumberUtil.convertValue(value.substring(0, 4), 3));
                if (instant.getPfa() == null && instant.getPfb() == null && instant.getPfc() == null && instant.getPf() == null) {
                    flag = false;
                }
                break;
            default:
                flag = false;
        }
        if (flag) {
            saveDataList.add(instant);
        }
    }

    private static void saveEvent(TransitControlTypeEnum controlType, String value, Integer pointId, List<Object> saveDataList) {
        if (value.length() < 24) {
            logger.info("{}'s length < 24");
            return;
        }
        String onTime = value.substring(0, 12);
        String offTime = value.substring(12);

        boolean flag = false;
        StringBuilder builder = new StringBuilder();
        builder.append("电表 停/上电事件 ");
        short status = EventStatusEnum.HAPPEN.getShortValue();
        Date dataTime = null;
        if (!"FFFFFFFFFFFF".equalsIgnoreCase(offTime)) {
            dataTime = DateUtil.StrToDate(offTime, DateUtil.TIME_LONG_12);
            builder.append(" 发生");
            flag = true;
        } else if (!"FFFFFFFFFFFF".equalsIgnoreCase(onTime)) {
            dataTime = DateUtil.StrToDate(onTime, DateUtil.TIME_LONG_12);
            status = EventStatusEnum.RECOVER.getShortValue();
            builder.append(" 恢复");
            flag = true;
        }
        if (flag) {
            //事件入库
            DataEvent event = new DataEvent();
            event.setObjId(pointId);
            event.setObjType(ObjectTypeEnum.OBJ_POINT.getShortValue());//22：终端事件;23：电表事件
            event.setEventItem(EVENT_POWER_CUT);
            event.setEventTime(dataTime);
            event.setUpdateTime(new Date());
            event.setStatus(status);
            event.setEventNote(builder.toString());
            saveDataList.add(event);
        }
    }

    private static PowerCumulant saveCumulant(TransitControlTypeEnum controlType, String value, Integer pointId, List<Object> saveDataList) {
        if (StringUtil.isEmpty(value)) {
            return null;
        }
        int length = 8;
        //根据报文长度计算费率数
        int maxCount = value.length() / length;

        Date now = new Date();
        Date dataTime = DateUtil.getCyc15Minute(now);

        String tempValue;
        int index = 0;
        short tariff = 0;
        BigDecimal decimal;

        PowerCumulant powerCumulant = new PowerCumulant();
        powerCumulant.setDataTime(dataTime);

        for (short count = 0; count < maxCount; count++) {
            index = count * length;
            if (index + length > value.length()) {
                logger.info("value's length:{} not enough, request length:{}.", value.length(), index + length);
                continue;
            }
            tempValue = value.substring(index, index + length);
            if (tempValue.indexOf("EE") == 0) {
                logger.info("value is EE");
                continue;
            }
            DataPowerCumulant cumulant = new DataPowerCumulant();
            cumulant.setPointId(pointId);
            cumulant.setDataTime(dataTime);
            tariff = (short) (maxCount - 1 - count);
            cumulant.setTariffType(tariff);
            cumulant.setPhaseType((short) 0);
            decimal = NumberUtil.convertValue(tempValue, 2);
            if (decimal == null) {
                continue;
            }

            switch (controlType) {
                case FORWARD_ACTIVE_ENERGY:
                    cumulant.setForwardActive(decimal);
                    break;
                case FORWARD_REACTIVE_ENERGY:
                    cumulant.setForwardReactive(decimal);
                    break;
                case REVERSE_ACTIVE_ENERGY:
                    cumulant.setReverseActive(decimal);
                    break;
                case REVERSE_REACTIVE_ENERGY:
                    cumulant.setReverseReactive(decimal);
                    break;
            }

            switch (tariff) {
                case 0:
                    powerCumulant.setTotal(decimal);
                    break;
                case 1:
                    powerCumulant.setSharp(decimal);
                    break;
                case 2:
                    powerCumulant.setPeak(decimal);
                    break;
                case 3:
                    powerCumulant.setFlat(decimal);
                    break;
                case 4:
                    powerCumulant.setValley(decimal);
                    break;
            }

            boolean flag = true;
            if (cumulant.getForwardActive() == null && cumulant.getForwardReactive() == null && cumulant.getReverseActive() == null && cumulant.getReverseReactive() == null) {
                flag = false;
            }
            if (flag) {
                saveDataList.add(cumulant);
            }
        }
        return powerCumulant;
    }

    private static void saveFreezeBlock(String value, Integer pointId, List<Object> saveDataList) {
        if (StringUtil.isEmpty(value)) {
            return;
        }
        int length = value.length();
        String freezeDataTime = value.substring(length - 10, length);
        if (!StringUtil.isDigits(freezeDataTime)) {
            logger.debug("{} 's date format is not correct.", freezeDataTime);
            return;
        }


        Date dataTime = DateUtil.StrToDate(freezeDataTime, "yyMMddHHmm");
        if (dataTime == null) {
            logger.debug("{} 's date format is not correct.", freezeDataTime);
            return;
        }

        String tempValue;
        int index = 0;
        BigDecimal decimal;

        int itemSize = 8;
        for (short count = 0; count < 2; count++) {
            index = count * (itemSize + 2);
            if (index + itemSize + 2 > value.length()) {
                logger.info("value's length:{} not enough, request length:{}.", value.length(), index + itemSize);
                continue;
            }
            tempValue = value.substring(index + 2, index + 2 + itemSize);
            if (tempValue.indexOf("EE") == 0) {
                logger.info("value is EE");
                continue;
            }
            DataPowerCumulant cumulant = new DataPowerCumulant();
            cumulant.setPointId(pointId);
            cumulant.setDataTime(dataTime);
            cumulant.setTariffType(TariffTypeEnum.TARRIF_ZONG.getShortValue());
            cumulant.setPhaseType((short) 0);
            decimal = NumberUtil.convertValue(tempValue, 2);
            if (decimal == null) {
                continue;
            }

            switch (count) {
                case 0:
                    cumulant.setReverseActive(decimal);
                    break;
                case 1:
                    cumulant.setForwardActive(decimal);
                    break;
            }

            boolean flag = true;
            if (cumulant.getForwardActive() == null && cumulant.getReverseActive() == null) {
                flag = false;
            }
            if (flag) {
                saveDataList.add(cumulant);
            }
        }
    }

    private static PointCommInfo parseCallData(byte[] byteValue, PointCommInfo pointComm) throws Exception {
        String value = ProtocolUtils.getByteToHexStringDesc(byteValue, byteValue.length, "");
        int index = value.length();
        index -= 18;
        String c = value.substring(index, index + 2);
        if ("91".equalsIgnoreCase(c) || "B1".equalsIgnoreCase(c)) {// 正常应答
            // 判断数据长度
            index -= 2;
            int len = Integer.parseInt(value.substring(index, index + 2), 16);
            if (len == 0) {// 无数据
                throw new Exception("回传645数据帧数据内容长度为0");
            }
            // 应答透明转发内容,数据域全部要减33的,长度L之后 到 CS校验和之前
            index -= len * 2;
            String temp = value.substring(index, index + len * 2);
            temp = makeDataSubtract33(temp);
            // 判断数据项
            index = temp.length();
            index -= 8;
            String di = temp.substring(index, index + 8).toUpperCase();
            // 数据域
            String data = temp.substring(0, index);
            if (ProtocolMeter645_2007Constant.RUN_STATUS_3.equals(di)) {
                // 电表运行状态字3
                return parseMeterRunStatus3(data, pointComm);//数据长度2字节
            } else if (ProtocolMeter645_2007Constant.CURRENT_SURPLUS_ENERGY.equals(di)) {
                // 当前剩余电量
                return parseMeterCurEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.CURRENT_OVERDRAW_ENERGY.equals(di)) {
                // 当前透支电量
                return parseMeterCurEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.CURRENT_SURPLUS_MONEY.equals(di)) {
                // 当前剩余金额
                return parseMeterCurEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.CURRENT_OVERDRAW_MONEY.equals(di)) {
                // 当前透支金额
                return parseMeterCurEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.CALL_DANXIANG.equals(di)) {
                // WiFi单相电能表主动上报数据
                return parseMeterWifiEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.CALL_SANXIANG.equals(di)) {
                // WiFi三相电能表主动上报数据
                return parseMeterWifiEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.ALARM_ENERGY1_LIMIT.equals(di)) {
                // 报警电量1限值
                return parseMeterCurEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.ALARM_ENERGY2_LIMIT.equals(di)) {
                // 报警电量2限值
                return parseMeterCurEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.HOARD_ENERGY_LIMIT.equals(di)) {
                // 囤积电量限值
                return parseMeterCurEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.OVERDRAW_ENERGY_LIMIT.equals(di)) {
                // 透支电量限值
                return parseMeterCurEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.ALARM_MONEY1_LIMIT.equals(di)) {
                // 报警金额1限值
                return parseMeterCurEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.ALARM_MONEY2_LIMIT.equals(di)) {
                // 报警金额2限值
                return parseMeterCurEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.HOARD_MONEY_LIMIT.equals(di)) {
                // 囤积金额限值
                return parseMeterCurEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.OVERDRAW_MONEY_LIMIT.equals(di)) {
                // 透支金额限值
                return parseMeterCurEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.CONNECT_MONEY_LIMIT.equals(di)) {
                // 合闸允许金额限值
                return parseMeterCurEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.TOTAL_BUY_MONEY_LAST.equals(di)) {
                // 上1次购电后累计购电金额
                return parseMeterCurEnergy(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.SERVER_IP_PORT.equals(di)) {
                // 接入地址
                return parseTianyiIot(di, data, pointComm);
            } else if (ProtocolMeter645_2007Constant.MODULE_VERSION.equals(di)) {
                // 模块软件版本号
                return parseTianyiIot(di, data, pointComm);
            }
        }
        return pointComm;
    }

    private static PointCommInfo parseMeterWifiEnergy(String di, String value, PointCommInfo pointComm) throws Exception {
        String reverseValue = ProtocolUtils.reverse(value, value.length());
        String resultData = "";
        int index = 0;
        Map<String, Object> resultValue = new HashMap<String, Object>();
        if (StringUtil.isEmpty(reverseValue) || reverseValue.length() != 50) {
            throw new Exception("回传645数据帧格式错误");
        }
        //组合有功总电能
        BigDecimal energyzong = new BigDecimal(ProtocolUtils.reverse(reverseValue.substring(index, index + 8), 8));
        energyzong = energyzong.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
        String valuezong = NumberUtil.formateScale2Str(energyzong);
        resultData += "组合有功总电能:" + valuezong + "kWh;";
        index = index + 8;
        //组合有功费率1电能
        BigDecimal energyjian = new BigDecimal(ProtocolUtils.reverse(reverseValue.substring(index, index + 8), 8));
        energyjian = energyjian.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
        String valuejian = NumberUtil.formateScale2Str(energyjian);
        resultData += "组合有功费率1电能:" + valuejian + "kWh;";
        index = index + 8;
        //组合有功费率2电能
        BigDecimal energyfen = new BigDecimal(ProtocolUtils.reverse(reverseValue.substring(index, index + 8), 8));
        energyfen = energyfen.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
        String valuefen = NumberUtil.formateScale2Str(energyfen);
        resultData += "组合有功费率2电能:" + valuefen + "kWh;";
        index = index + 8;
        //组合有功费率3电能
        BigDecimal energypin = new BigDecimal(ProtocolUtils.reverse(reverseValue.substring(index, index + 8), 8));
        energypin = energypin.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
        String valuepin = NumberUtil.formateScale2Str(energypin);
        resultData += "组合有功费率3电能:" + valuepin + "kWh;";
        index = index + 8;
        //组合有功费率4电能
        BigDecimal energygu = new BigDecimal(ProtocolUtils.reverse(reverseValue.substring(index, index + 8), 8));
        energygu = energygu.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
        String valuegu = NumberUtil.formateScale2Str(energygu);
        resultData += "组合有功费率4电能:" + valuegu + "kWh;";
        index = index + 8;
        //电压
        BigDecimal u = new BigDecimal(ProtocolUtils.reverse(reverseValue.substring(index, index + 4), 4));
        u = u.divide(BigDecimal.valueOf(10), 1, RoundingMode.HALF_UP);
        String valueU = NumberUtil.formateScale2Str(u);
        resultData += "电压:" + valueU + "V;";
        index = index + 4;
        //电流
        BigDecimal i = new BigDecimal(ProtocolUtils.reverse(reverseValue.substring(index, index + 6), 6).substring(1));
        i = i.divide(BigDecimal.valueOf(1000), 3, RoundingMode.HALF_UP);
        String valueI = NumberUtil.formateScale2Str(i);
        resultData += "电流:" + valueI + "A;";
        index = index + 6;

        pointComm.setResultData(resultData);
        pointComm.setResultValue(resultValue);
        return pointComm;
    }

    private static PointCommInfo parseMeterRunStatus3(String value, PointCommInfo pointComm) throws Exception {
        String resultData = "";
        Map<String, Object> resultValue = new HashMap<String, Object>();
        if (StringUtil.isEmpty(value) || value.length() != 4) {
            throw new Exception("回传645数据帧格式错误");
        }

        String temp = value.substring(2);
        int num = Integer.parseInt(temp, 16);
        temp = Integer.toBinaryString(num);
        temp = StringUtil.AddjustLength(temp, 8, "0");

        String b = temp.substring(3, 4); //电表运行状态字3 bit4
        resultValue.put("powerStatus", Integer.parseInt(b));
        pointComm.setResultData(resultData);
        pointComm.setResultValue(resultValue);
        return pointComm;
    }

    private static PointCommInfo parseTianyiIot(String di, String value, PointCommInfo pointComm) throws Exception {
        String resultData = "";
        Map<String, Object> resultValue = new HashMap<String, Object>();

        value = ProtocolUtils.reverse(value, value.length());
        byte[] bytes = ProtocolUtils.StringToHex(value);
        value = ProtocolUtils.ascii2String(bytes, 1, bytes.length - 1);

        if (ProtocolMeter645_2007Constant.MODULE_VERSION.equals(di)) {
            resultData = "模块版本号:" + value;
            resultValue.put("moduleVersion", value);
        } else if (ProtocolMeter645_2007Constant.SERVER_IP_PORT.equals(di)) {
            resultData = "接入地址:" + value;
            resultValue.put("serverIpPort", value);
        }
        pointComm.setResultData(resultData);
        pointComm.setResultValue(resultValue);
        return pointComm;
    }

    private static PointCommInfo parseMeterCurEnergy(String di, String value, PointCommInfo pointComm) throws Exception {
        String resultData = "";
        Map<String, Object> resultValue = new HashMap<String, Object>();
        if (StringUtil.isEmpty(value) || value.length() != 8) {
            throw new Exception("回传645数据帧格式错误");
        }
        BigDecimal valuenum = new BigDecimal(value);
        valuenum = valuenum.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);

        String valuestr = NumberUtil.formateScale2Str(valuenum);

        if (ProtocolMeter645_2007Constant.CURRENT_SURPLUS_ENERGY.equals(di)) {
            resultData = "当前剩余电量:" + valuestr + "kwh;";
            resultValue.put("surplusEnergy", new BigDecimal(valuestr));
        } else if (ProtocolMeter645_2007Constant.CURRENT_OVERDRAW_ENERGY.equals(di)) {
            resultData = "当前透支电量:" + valuestr + "kwh;";
            resultValue.put("overdrawEnergy", new BigDecimal(valuestr));
        } else if (ProtocolMeter645_2007Constant.CURRENT_SURPLUS_MONEY.equals(di)) {
            resultData = "当前剩余金额:" + valuestr + ";";
            resultValue.put("surplusMoney", new BigDecimal(valuestr));
        } else if (ProtocolMeter645_2007Constant.CURRENT_OVERDRAW_MONEY.equals(di)) {
            resultData = "当前透支金额:" + valuestr + ";";
            resultValue.put("overdrawMoney", new BigDecimal(valuestr));
        } else if (ProtocolMeter645_2007Constant.ALARM_ENERGY1_LIMIT.equals(di)) {
            resultData = "报警电量1限值:" + valuestr + ";";
            resultValue.put("alarmEnergy1Limit", new BigDecimal(valuestr));
        } else if (ProtocolMeter645_2007Constant.ALARM_ENERGY2_LIMIT.equals(di)) {
            resultData = "报警电量2限值:" + valuestr + ";";
            resultValue.put("alarmEnergy2Limit", new BigDecimal(valuestr));
        } else if (ProtocolMeter645_2007Constant.HOARD_ENERGY_LIMIT.equals(di)) {
            resultData = "囤积电量限值:" + valuestr + ";";
            resultValue.put("hoardEnergyLimit", new BigDecimal(valuestr));
        } else if (ProtocolMeter645_2007Constant.OVERDRAW_ENERGY_LIMIT.equals(di)) {
            resultData = "透支电量限值:" + valuestr + ";";
            resultValue.put("overdrawEnergyLimit", new BigDecimal(valuestr));
        } else if (ProtocolMeter645_2007Constant.ALARM_MONEY1_LIMIT.equals(di)) {
            resultData = "报警金额1限值:" + valuestr + ";";
            resultValue.put("alarmMoney1Limit", new BigDecimal(valuestr));
        } else if (ProtocolMeter645_2007Constant.ALARM_MONEY2_LIMIT.equals(di)) {
            resultData = "报警金额2限值:" + valuestr + ";";
            resultValue.put("alarmMoney2Limit", new BigDecimal(valuestr));
        } else if (ProtocolMeter645_2007Constant.HOARD_MONEY_LIMIT.equals(di)) {
            resultData = "透支金额限值:" + valuestr + ";";
            resultValue.put("hoardMoneyLimit", new BigDecimal(valuestr));
        } else if (ProtocolMeter645_2007Constant.OVERDRAW_MONEY_LIMIT.equals(di)) {
            resultData = "囤积金额限值:" + valuestr + ";";
            resultValue.put("overdrawMoneyLimit", new BigDecimal(valuestr));
        } else if (ProtocolMeter645_2007Constant.CONNECT_MONEY_LIMIT.equals(di)) {
            resultData = "合闸允许金额限值:" + valuestr + ";";
            resultValue.put("connectMoneyLimit", new BigDecimal(valuestr));
        } else if (ProtocolMeter645_2007Constant.TOTAL_BUY_MONEY_LAST.equals(di)) {
            resultData = "上1次购电后累计购电金额:" + valuestr + ";";
            resultValue.put("totalBuyMoneyLast", new BigDecimal(valuestr));
        }
        if (StringUtil.isEmpty(valuestr)) {
            pointComm.setResultObject(null);
        } else {
            pointComm.setResultObject(new BigDecimal(valuestr));
        }

        pointComm.setResultData(resultData);
        pointComm.setResultValue(resultValue);
        return pointComm;
    }

    public static String makeDataSubtract33(String data) {
        String result = "";
        int num = 0;
        String temp;
        for (int i = 0; i < data.length() / 2; i++) {
            temp = data.substring(i * 2, i * 2 + 2);
            num = Integer.parseInt(temp, 16) - 0x33;
            num = ProtocolUtils.Unsignd((byte) num);
            result += StringUtil.AddjustLength(NumberUtil.num2PadString(num, 16, 2, "0"), 2, "0");
        }
        return result;
    }

    private static String errMessage(byte b) {
        String errCode = makeDataSubtract33(String.format("%02X", ProtocolUtils.Unsignd(b)));
        String errStr = "${" + Integer.parseInt(makeDataSubtract33(String.format("%02X", ProtocolUtils.Unsignd(b))), 16) + "}" + "表计异常应答:";
        if ("C".equalsIgnoreCase(errCode.substring(0, 1))) {//卡表错误码
            int err = Integer.parseInt(makeDataSubtract33(String.format("%02X", ProtocolUtils.Unsignd(b))), 16) - 192;
            switch (err) {
                case 1:
                    errStr += "表号不对应错误(卡表);";
                    break;
                case 2:
                    errStr += "读下行数据错误(卡表) ;";
                    break;
                case 4:
                    errStr += "系统注册码错误(卡表) ;";
                    break;
                case 6:
                    errStr += "仪表工作模式不对应(卡表);";
                    break;
                case 7:
                    errStr += "超过囤积限量9999kWh(卡表);";
                    break;
                case 8:
                    errStr += "出厂编号不对应(卡表);";
                    break;
                case 9:
                    errStr += "购电次数错误(卡表);";
                    break;
                case 10:
                    errStr += "上电超2分钟，清零超时(卡表);";
                    break;
                default:
                    errStr = errStr + "其他错误,errCode=" + err + "(卡表);";
                    break;
            }
        } else {
            int err = Integer.parseInt(makeDataSubtract33(String.format("%02X", ProtocolUtils.Unsignd(b))), 16);
            for (int i = 0; i < 7; i++) {
                if (((err >> i) & 0x01) == 1) {
                    switch (i) {
                        case 0:
                            errStr += "其他错误;";
                            break;
                        case 1:
                            errStr += "无请求数据;";
                            break;
                        case 2:
                            errStr += "密码错/未授权;";
                            break;
                        case 3:
                            errStr += "通信速率不能更改;";
                            break;
                        case 4:
                            errStr += "年时区数超;";
                            break;
                        case 5:
                            errStr += "日时段数超;";
                            break;
                        case 6:
                            errStr += "费率数超 ;";
                            break;
                    }
                }
            }
        }
        return errStr;
    }
}
